home *** CD-ROM | disk | FTP | other *** search
- /*
- * A version of Ward Christensen's file transfer protocol for
- * Unix System V or 4.2 bsd.
- *
- * Emmet P. Gray, ..!ihnp4!uiucuxc!fthood!egray, 16 Aug 85
- *
- * Modified by Sanford Zelkovitz 08/18/86
- * Last modification date = 05/20/87
- * Modified for KA9Q NOS BBS - WA3DSP 2/93
- */
-
-
- #include "global.h"
- #include <sys/stat.h>
- #include <stdarg.h>
- #include "dirutil.h"
- #include "timer.h"
- #include "socket.h"
- #include "mailbox.h"
-
- #if !defined(_lint)
- static char rcsid[] OPTIONAL = "$Id: xmodem.c,v 1.15 1997/07/31 00:44:20 root Exp root $";
- #endif
-
- #if defined(TIPMAIL) && defined(XMODEM)
-
- #ifdef min
- #undef min
- #endif
-
-
- #define SPEED 2400 /* Serial line Baudrate */
-
- #define MAXERRORS 10 /* max number of times to retry */
- #define SECSIZE 128 /* CP/M sector, transmission block */
- #define CPMEOF 26 /* End Of File (for CP/M) */
- #ifndef SOH
- #define SOH 1 /* Start Of Header */
- #define STX 2 /* Start of 1K block */
- #define EOT 4 /* End Of Transmission */
- #endif
- #define ACK 6 /* ACKnowledge */
- #define NAK 21 /* Negative AcKnowledge */
- #define CAN 24 /* CANcel */
- #ifndef BS
- #define BS 8 /* Backspace */
- #endif
-
-
- static int xm_recvfile (char *, struct mbx * m);
- static int xm_sendfile (char *, struct mbx * m);
- static unsigned char getchar_t (int thesocket);
- static void update_crc (unsigned char c, unsigned char *crc1, unsigned char *crc2);
- static void error (struct mbx * m);
- static void print_text (struct mbx * m, const char *fmt,...);
- static void rawmode (struct mbx *);
- static void restoremode (struct mbx *);
-
-
-
- int
- doxmodem (char mode, char *filename, void *p)
- {
- int exit_return = 0, oldflush;
- struct mbx *m;
-
- m = (struct mbx *) p;
- oldflush = setflush (m->user, -1);
-
- switch (mode) {
- case 'r':
- case 'R':
- exit_return = xm_recvfile (filename, m);
- break;
- case 's':
- case 'S':
- exit_return = xm_sendfile (filename, m);
- break;
- default:
- print_text (m, "Xmodem: Invalid Option\n");
- }
- restoremode (m);
- usputc (m->user, '\n');
- usflush (m->user);
- (void) setflush (m->user, oldflush);
- return (exit_return);
- }
-
-
-
- /* send a file to the remote */
- static int
- xm_sendfile (char *tfile, struct mbx *m)
- {
- FILE *fp;
- unsigned char chr, thechecksum, block, sector[SECSIZE];
- unsigned char crc1, crc2, mode, errcount, errcount2, two_can;
- int i, nbytes, speed = SPEED;
- long size, min, sec;
-
- if ((size = fsize (tfile)) == -1) {
- print_text (m, "xmodem: Can't open '%s' for read\n", tfile);
- return (1);
- }
- if ((fp = fopen (tfile, READ_BINARY)) == NULLFILE) {
- print_text (m, "xmodem: Can't open '%s' for read\n", tfile);
- return (1);
- }
- size = (size / 128L) + 1L;
- sec = size * 128L * 15L / speed;
- min = sec / 60L;
- sec = sec - min * 60L;
- print_text (m, "\nFile open: %d records\n", size);
- print_text (m, "Send time: %ld min, %ld sec at %d baud\n", min, sec, speed);
- print_text (m, "To cancel: use CTRL-X numerous times\n");
- print_text (m, "Waiting receive ready signal\n");
-
- kpause (3000L);
- rawmode (m);
- errcount = 0;
- mode = 0;
- two_can = 0;
- block = 1;
-
- while (errcount < MAXERRORS) {
- chr = getchar_t (m->user);
- if (chr == NAK) /* checksum mode */
- break;
- if (chr == 'C') { /* CRC mode */
- mode = 1;
- break;
- }
- if (chr == CAN) {
- if (two_can) {
- kpause (3000L);
- print_text (m, "\nxmodem: Abort request received\n");
- (void) fclose (fp);
- return (1);
- }
- two_can = 1;
- } else
- two_can = 0;
-
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- kpause (3000L);
- print_text (m, "xmodem: Timed out on acknowledge\n");
- (void) fclose (fp);
- return (1);
- }
- two_can = 0;
- while ((nbytes = (int) fread (sector, 1, 128, fp)) != 0) {
- if (nbytes < SECSIZE) { /* fill short sector */
- for (i = nbytes; i < SECSIZE; i++)
- sector[i] = CPMEOF;
- }
- errcount = 0;
- while (errcount < MAXERRORS) {
- usputc (m->user, SOH); /* the header */
- usputc (m->user, block); /* the block number */
- chr = ~block;
- usputc (m->user, chr); /* it's complement */
- thechecksum = 0;
- crc1 = 0;
- crc2 = 0;
- for (i = 0; i < SECSIZE; i++) {
- usputc (m->user, sector[i]);
- if (mode)
- update_crc (sector[i], &crc1, &crc2);
- else
- thechecksum += sector[i];
- }
- if (mode) {
- update_crc (0, &crc1, &crc2);
- update_crc (0, &crc1, &crc2);
- usputc (m->user, crc1);
- usputc (m->user, crc2);
-
- } else
- usputc (m->user, thechecksum);
-
- usflush (m->user);
- errcount2 = 0;
- rec_loop:
-
- chr = getchar_t (m->user);
- if (chr == CAN) {
- if (two_can) {
- kpause (3000L);
- print_text (m, "\nxmodem: Abort request received\n");
- (void) fclose (fp);
- return (1);
- }
- two_can = 1;
- } else
- two_can = 0;
-
- if (chr == ACK)
- break; /* got it! */
- /* noise on line? */
- if (chr != NAK) {
- ++errcount2;
- if (errcount2 >= MAXERRORS) {
- error (m);
- (void) fclose (fp);
- return 1;
- }
- goto rec_loop;
- }
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- error (m);
- (void) fclose (fp);
- return (1);
- }
- block++;
- }
- errcount = 0;
- while (errcount < MAXERRORS) {
- usputc (m->user, EOT);
- usflush (m->user);
- if (getchar_t (m->user) == ACK) {
- (void) fclose (fp);
- kpause (6000L);
- log (m->user, "Xmodem: Download - %s", tfile);
- print_text (m, "Xmodem: File sent OK\n");
- return (0);
- }
- errcount++;
- }
- (void) fclose (fp);
- kpause (3000L);
- error (m);
- return (1);
- }
-
-
-
- /* receive a file from the remote */
- static int
- xm_recvfile (char *tfile, struct mbx *m)
- {
- FILE *fp;
- unsigned char hdr, blk, cblk, tmp, thecksum = 0, crc1, crc2;
- unsigned char c1 = 0, c2 = 0, sum, block, sector[SECSIZE];
- unsigned char first, mode = 0, errcount, two_can;
- int i;
-
- if (!access (tfile, 00)) {
- print_text (m, "xmodem: File %s already exists\n", tfile);
- return (1);
- }
- if ((fp = fopen (tfile, WRITE_BINARY)) == NULLFILE) {
- print_text (m, "xmodem: Can't open '%s' for write\n", tfile);
- return (1);
- }
- print_text (m, "File open - ready to receive\n");
- print_text (m, "To cancel: use CTRL-X numerous times\n");
- kpause (3000L);
- rawmode (m);
- errcount = 0;
- block = 1;
- first = 0;
- two_can = 0;
-
- kpause (3000L);
- while (errcount < MAXERRORS) {
- if (errcount < (MAXERRORS / 2)) {
- usputc (m->user, 'C'); /* try CRC mode first */
- usflush (m->user);
- mode = 1;
- } else {
- usputc (m->user, NAK); /* then checksum */
- usflush (m->user);
- mode = 0;
- }
- if ((hdr = getchar_t (m->user)) == SOH) {
- first = 1;
- break;
- }
- if (hdr == CAN) {
- if (two_can) {
- kpause (3000L);
- print_text (m, "\nxmodem: Abort request received\n");
- (void) fclose (fp);
- unlink (tfile);
- return (1);
- }
- two_can = 1;
- } else
- two_can = 0;
- errcount++;
- }
- if (errcount >= MAXERRORS) {
- kpause (3000L);
- print_text (m, "\nxmodem: Timed out on acknowledge\n");
- (void) fclose (fp);
- unlink (tfile);
- return (1);
- }
- errcount = 0;
- two_can = 0;
- while (errcount < MAXERRORS) {
-
- if (first) {
- hdr = SOH;
- first = 0;
- } else
- hdr = getchar_t (m->user);
-
- if (hdr == CAN) {
- if (two_can) {
- kpause (3000L);
- print_text (m, "\nxmodem: Abort request received\n");
- (void) fclose (fp);
- unlink (tfile);
- return (1);
- }
- two_can = 1;
- continue;
- } else
- two_can = 0;
-
- if (hdr == EOT) /* done! */
- break;
-
- if (hdr != SOH) { /* read in junk for 6 seconds */
- kalarm (6000L);
- while (errno != EALARM)
- (void) rrecvchar (m->user);
- kalarm (0L); /* cancel alarm */
- first = 0;
- goto nak;
- }
- blk = getchar_t (m->user);
- cblk = getchar_t (m->user);
- crc1 = 0;
- crc2 = 0;
- sum = 0;
- for (i = 0; i < SECSIZE; i++) {
- sector[i] = getchar_t (m->user);
- if (mode)
- update_crc (sector[i], &crc1, &crc2);
- else
- sum += sector[i];
- }
- if (mode) {
- c1 = getchar_t (m->user);
- c2 = getchar_t (m->user);
- } else
- thecksum = getchar_t (m->user);
- if (blk != block && blk != (block - 1))
- goto nak;
- tmp = ~blk;
- if (cblk != tmp)
- goto nak;
- if (mode) {
- update_crc (0, &crc1, &crc2);
- update_crc (0, &crc1, &crc2);
- if (c1 != crc1 || c2 != crc2)
- goto nak;
- } else {
- if (thecksum != sum)
- goto nak;
- }
- if (block == blk) {
- (void) fflush (fp);
- if (fwrite (sector, sizeof (sector[0]), SECSIZE, fp) != SECSIZE) {
- error (m);
- print_text (m, " File write error - Partial file deleted\n");
- (void) fclose (fp);
- unlink (tfile);
- return (1);
- }
- }
- block = blk + 1;
- usputc (m->user, ACK); /* got it! */
- usflush (m->user);
- errcount = 0;
- continue;
-
- nak:
- usputc (m->user, NAK);
- /* do it over */
- usflush (m->user);
- errcount++;
- }
- if (errcount == MAXERRORS) {
- error (m);
- (void) fclose (fp);
- unlink (tfile);
- return (1);
- }
- usputc (m->user, ACK);
- usflush (m->user);
- kpause (3000L);
- (void) fclose (fp);
- log (m->user, "Xmodem: Upload - %s", tfile);
- print_text (m, "Xmodem: File received OK\n");
- return (0);
- }
-
-
-
- /* exceeded the maximum number of retry's */
- static void
- error (struct mbx *m)
- {
- int i;
-
- for (i = 0; i < 9; i++)
- usputc (m->user, CAN);
-
- usflush (m->user);
- kpause (1000L);
- for (i = 0; i < 9; i++)
- usputc (m->user, BS);
-
- usflush (m->user);
- kpause (3000L);
- print_text (m, "\nxmodem: Exceeded error limit...aborting\n");
- return;
- }
-
-
-
- /* update the CRC bytes */
- static void
- update_crc (unsigned char c, unsigned char *crc1, unsigned char *crc2)
- {
- register int i, temp;
- register unsigned char carry, c_crc1, c_crc2;
-
- for (i = 0; i < 8; i++) {
- temp = c * 2;
- c = uchar(temp); /* rotate left */
- carry = ((temp > 255) ? 1 : 0);
- temp = *crc2 * 2;
- *crc2 = uchar(temp);
- *crc2 |= carry; /* rotate with carry */
- c_crc2 = ((temp > 255) ? 1 : 0);
- temp = *crc1 * 2;
- *crc1 = uchar(temp);
- *crc1 |= c_crc2;
- c_crc1 = ((temp > 255) ? 1 : 0);
- if (c_crc1) {
- *crc2 ^= 0x21;
- *crc1 ^= 0x10;
- }
- }
- return;
- }
-
-
-
- /* getchar with a 5 sec time out */
- static unsigned char
- getchar_t (int s)
- {
- unsigned char c;
-
- /* only have 5 sec... */
- kalarm (5000L);
- /* Wait for something to happen */
- c = uchar(rrecvchar (s));
- kalarm (0L);
- return (c);
- }
-
-
-
- /* put the stdin/stdout in the "raw" mode */
- static void
- rawmode (struct mbx *m)
- {
- (void) seteol (m->user, 0);
- (void) seteol (m->tip->s, 0);
- (void) sockmode (m->tip->s, SOCK_BINARY);
- (void) sockmode (m->user, SOCK_BINARY);
- m->tip->raw = 1;
- }
-
-
-
- static void
- restoremode (struct mbx *m)
- {
- while (socklen (m->user, 0) != 0)
- (void) recv_mbuf (m->user, NULL, 0, NULLCHAR, 0);
- (void) seteol (m->user, "\n");
- (void) seteol (m->tip->s, "\n");
- (void) sockmode (m->user, SOCK_ASCII);
- (void) sockmode (m->tip->s, SOCK_ASCII);
- m->tip->raw = 0;
- }
-
-
-
- void
- #ifdef TNOS_68K
- print_text (m, fmt)
- struct mbx *m;
- const char *fmt;
- #else
- print_text (struct mbx *m, const char *fmt,...)
- #endif
- {
- va_list ap;
- char buf[80];
-
- restoremode (m);
- va_start (ap, fmt); /*lint !e718 !e746 */
- (void) vsprintf (buf, fmt, ap);
- va_end (ap);
- usprintf (m->user, buf);
- usflush (m->user);
- }
-
- #endif
-